package czh.cocoa.ui.impl;

import static czh.cocoa.graphics.CGContext.CGContextSetFillColorWithColor;
import static czh.cocoa.ui.UIKit.UIGraphicsGetCurrentContext;
import android.graphics.Paint;
import czh.cocoa.animation.CABasicAnimation;
import czh.cocoa.animation.CALayer;
import czh.cocoa.animation.CAMediaTimingFunction;
import czh.cocoa.foundation.NSArray;
import czh.cocoa.foundation.NSMutableArray;
import czh.cocoa.foundation.NSMutableDictionary;
import czh.cocoa.foundation.NSMutableString;
import czh.cocoa.foundation.NSNumber;
import czh.cocoa.foundation.NSObject;
import czh.cocoa.foundation.NSSet;
import czh.cocoa.foundation.NSString;
import czh.cocoa.graphics.CGContext;
import czh.cocoa.graphics.CGFont;
import czh.cocoa.graphics.CGPoint;
import czh.cocoa.graphics.CGRect;
import czh.cocoa.graphics.CGSize;
import czh.cocoa.ui.UIColor;
import czh.cocoa.ui.UIEvent;
import czh.cocoa.ui.UIFont;
import czh.cocoa.ui.UIKeyInput;
import czh.cocoa.ui.UITouch;
import czh.cocoa.ui.UIView;

public class UITextView extends UIScrollView implements UIKeyInput {
	
	private final static float EDIT_CURSOR_WIDTH = 5;
	private final static float TEXT_CONTENT_PADDING = 10;

	private UIWebDocumentView mDocView;
	
	private NSMutableString mText;
	
	private UIColor mTextColor;
	
	private UIFont mFont;
	
	private UIView mCursorView;
	
	private NSString[] mTextSections;
	
	private CGRect[] mTextSectionRects;
	
	private int mEditIndex;
	
	public UITextView() {
		
	}
	
	public UITextView(CGRect frame) {
		super(frame);
	}
	
	protected void init() {
		super.init();
		mText = new NSMutableString();
		mTextColor = UIColor.blackColor();
		mFont = UIFont.systemFontOfSize(20);
		
		float padding = TEXT_CONTENT_PADDING;
		mDocView = new UIWebDocumentView(CGRectMake(padding, padding, -padding*2, 0));
		mDocView.setAutoresizingMask(UIViewAutoresizingFlexibleWidth); 
		addSubview(mDocView);
		
		mCursorView = new UIView(); 
		mCursorView.setHidden(true);
		mCursorView.setBackgroundColor(new UIColor(45/255f, 90/255f, 240/255f, 1)); 
		mDocView.addSubview(mCursorView);
	}
	
	public void setText(NSString text) {
		mText.setString(text);
		adjustDocumentViewBounds();
	}
	
	public NSString text() {
		return new NSString(mText);
	}
	
	public void setTextColor(UIColor color) {
		mTextColor = color;
		mDocView.setNeedsDisplay();
	}
	
	public UIColor textColor() {
		return mTextColor;
	}
	
	public void setFont(UIFont font) {
		mFont = font;
		adjustDocumentViewBounds();
	}
	
	public UIFont font() {
		return mFont;
	}

	private void adjustDocumentViewBounds() {
		CGRect bounds = mDocView.bounds();
		
		NSMutableString text = new NSMutableString(text());
		boolean newline_ended = text.substringFromIndex(text.length() - 1).isEqual(NSTR("\n"));  
		if (newline_ended) { 
			text.appendString(NSTR("\n#"));   // "\n\nd"
		}
		
		//NSLog("adjust text: %s", text); 
		
		NSArray sections = text.componentsSeparatedByString(NSTR("\n")); 
		
		float offy = 0;
		
		int count = newline_ended ? sections.count() - 1 : sections.count();
		mTextSections = new NSString[count];
		mTextSectionRects = new CGRect[count];
		
		//NSLog("section count: %d", count);
		
		float lineh = mFont.ascender() - mFont.descender();
		CGSize size0 = CGSizeMake(bounds.size.width, INT32_MAX); 
		
		for (int i = 0; i < count; i++) {
			NSString section = (NSString) sections.objectAtIndex(i); 
			mTextSections[i] = section;
			
			CGSize size;
			if (section.length() > 0) { 
				size = section.sizeWithFontConstrainedToSize(mFont, size0);
			} else {
				size = CGSizeMake(bounds.size.width, lineh);
			}
			
			CGRect rect = CGRectMake(0, offy, bounds.size.width, size.height); 
			mTextSectionRects[i] = rect;
			
			offy += size.height;
		}
		
		bounds.size.height = offy;
		mDocView.setBounds(bounds);
		
		CGSize content_size = bounds().size;
		content_size.height = offy + TEXT_CONTENT_PADDING * 2;
		setContentSize(content_size);
		
		mDocView.setNeedsDisplay();
	}
	
	private void setCursorAnimationVisible(boolean visible) {
		if (visible) { 
			if (mCursorView.isHidden()) { 
				mCursorView.setHidden(false);
				CABasicAnimation anim = new CABasicAnimation(CALayer.ANIM_OPACITY);
				anim.setFromValue(new NSNumber(1));
				anim.setToValue(new NSNumber(0));
				anim.setRepeatCount(HUGE_VALF);
				anim.setAutoreverses(true);
				anim.setDuration(0.5);
				anim.setTimingFunction(CAMediaTimingFunction.EaseIn);
				mCursorView.layer().addAnimationForKey(anim, null);
			}
		} else {
			if (!mCursorView.isHidden()) { 
				mCursorView.setHidden(true);
				mCursorView.layer().removeAllAnimations();
			}
		}
	}
	
	private void showCursorViewInLocation(CGPoint location) {
		if (!hasText()) { 
			float lineh = mFont.ascender() - mFont.descender();
			mCursorView.setFrame(CGRectMake(0, 0, EDIT_CURSOR_WIDTH, lineh)); 
			setCursorAnimationVisible(true);
			mEditIndex = 0;
			return;
		}
		
		boolean done = false;
		CGRect bounds = mDocView.bounds();
		int char_index = 0;
		
		for (int i = 0; i < mTextSections.length; i++) { 
			NSString section = mTextSections[i];
			CGRect rect = mTextSectionRects[i]; 
			
			//NSLog("section rect: %s", rect); 
			
			if (rect.containsPoint(location) || i == mTextSections.length - 1) { 
				
				float lineh = mFont.ascender() - mFont.descender();
				
				if (section.length() == 0) {  // "\n"
					mCursorView.setFrame(CGRectMake(rect.origin.x, rect.origin.y, 
							EDIT_CURSOR_WIDTH, lineh)); 
					setCursorAnimationVisible(true);
					mEditIndex = char_index;
					break;
				}
				
				CGPoint point = CGPointMake(location.x - rect.origin.x, location.y - rect.origin.y);
				
				Paint paint = new Paint();
				CGFont font = new CGFont(mFont.fontName());
				paint.setTypeface(font.typeface());
				paint.setTextSize(mFont.pointSize());
				
				String words = section.toString();
				float[] widths = new float[words.length()];
				int count = paint.getTextWidths(words, widths);
				CGPoint cursor = CGPointMake(0, 0);
				
				for (int j = 0; j < count; j++) {
					float width = widths[j];
					if (cursor.x + width > bounds.size.width) {
						cursor.x = 0;
						cursor.y += lineh;
					}
					if (CGRectMake(cursor.x, cursor.y, width, lineh).containsPoint(point) ||
							j == count - 1) {  
						float c_width = EDIT_CURSOR_WIDTH;
						float c_height = lineh;
						float x = rect.origin.x + cursor.x + width;
						float y = rect.origin.y + cursor.y;
						mCursorView.setFrame(CGRectMake(x, y, c_width, c_height)); 
						setCursorAnimationVisible(true);
						
						mEditIndex = char_index + j + 1;
						
						done = true;
						break;
					}
					cursor.x += width;
				}
			}
			
			if (done) {
				break;
			}
			
			char_index += section.length() + 1;  //include "\n"
		}
	}
	
	private void showCursorViewAtEditIndex() {
		CGRect bounds = mDocView.bounds();
		int char_index = 0;
		
		for (int i = 0; i < mTextSections.length; i++) { 
			NSString section = mTextSections[i];
			CGRect rect = mTextSectionRects[i]; 
			
			//NSLog("section rect: %s", rect); 
			
			if (mEditIndex >= char_index && mEditIndex <= char_index + section.length()) { 
				
				int index = mEditIndex - char_index;
				
				float lineh = mFont.ascender() - mFont.descender();
				
				Paint paint = new Paint();
				CGFont font = new CGFont(mFont.fontName());
				paint.setTypeface(font.typeface());
				paint.setTextSize(mFont.pointSize());
				
				String words = section.toString();
				float[] widths = new float[words.length()];
				paint.getTextWidths(words, widths);
				CGPoint cursor = CGPointMake(0, 0);
				
				for (int j = 0; j < index; j++) {
					float width = widths[j];
					if (cursor.x + width > bounds.size.width) {
						cursor.x = width;
						cursor.y += lineh;
					} else {
						cursor.x += width;
					}
				}
				
				float c_width = EDIT_CURSOR_WIDTH;
				float c_height = lineh;
				float x = rect.origin.x + cursor.x;
				float y = rect.origin.y + cursor.y;
				mCursorView.setFrame(CGRectMake(x, y, c_width, c_height)); 
				
			}
			
			char_index += section.length() + 1;  //include "\n"
		}
	}
	
	public void touchesEndedWithEvent(NSSet touches, UIEvent event) {
		UITouch touch = event.firstTouch();
		CGPoint location = touch.locationInView(this); 
		CGRect bounds = bounds();
		location.x += bounds.origin.x - TEXT_CONTENT_PADDING;
		location.y += bounds.origin.y - TEXT_CONTENT_PADDING;
		showCursorViewInLocation(location);
		becomeFirstResponder();
	}
	
	@Override
	public int keyboardType() {
		return UIKeyboardTypeDefault;
	}

	@Override
	public boolean hasText() {
		return mText.length() > 0;
	}

	@Override
	public void insertText(NSString text) {
		mText.insertStringAtIndex(text, mEditIndex);
		adjustDocumentViewBounds();
		mEditIndex += text.length();
		showCursorViewAtEditIndex(); 
	}

	@Override
	public void deleteBackward() {
		if (mEditIndex > 0) { 
			mText.deleteCharactersInRange(NSMakeRange(mEditIndex - 1, 1));
			adjustDocumentViewBounds();
			mEditIndex -= 1;
			showCursorViewAtEditIndex();
		}
	}
	
	public boolean canBecomeFirstResponder() {
		return true;
	}
	
	public boolean resignFirstResponder() {
		boolean ret = super.resignFirstResponder();
		if (ret) {
			setCursorAnimationVisible(false);
		}
		return ret;
	}
	
	private class UIWebDocumentView extends UIView {
		
		public UIWebDocumentView(CGRect frame) {
			super(frame);
		}
		
		public void drawRect(CGRect rect) {
			CGContext ctx = UIGraphicsGetCurrentContext();
			CGContextSetFillColorWithColor(ctx, mTextColor.CGColor());
			
			CGRect bounds = bounds();
			NSString text = text();
			NSArray sentences = text.componentsSeparatedByString(NSTR("\n")); 
			
			float offy = 0;
			float lineh = mFont.ascender() - mFont.descender();
			
			for (int i = 0; i < sentences.count(); i++) {
				NSString sentence = (NSString) sentences.objectAtIndex(i); 
				CGRect region = CGRectMake(0, offy, bounds.size.width, bounds.size.height - offy); 
				CGSize size = sentence.drawInRectWithFont(region, mFont);
				offy += size.height > 0 ? size.height : lineh;
			}
		}
		
	}
	
}
